import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import IA.Energia.Centrales;
import IA.Energia.Clientes;
import aima.search.framework.Problem;
import aima.search.framework.Search;
import aima.search.framework.SearchAgent;
import aima.search.informed.HillClimbingSearch;
import aima.search.informed.SimulatedAnnealingSearch;


public class Experimento5 implements IExperiment {
	List<List<String>> result = new ArrayList<List<String>>();
	double prTipos[];
	double prContratos;
	int tiposCentrales[];
	int nclientes;
	int numreplicas;
	boolean operador[];
	int solucionInicial;
	int It; // El numero maximo de iteraciones
	int incIt;
	int finIt;
	int ItP; // El numero de iteraciones por cada paso de temperatura
	int incItP;
	int finItP;
	int K; // k
	int inck;
	int fink;
	double L; // Lambda
	double incLambda;
	double finLambda;
	int pn;
	int incPn;
	int finPn;
	String nombre;
	List<String> cols = new ArrayList<String>();
	
	public Experimento5(String nombre, boolean[] operadores, int numreplicas, int solucionInicial, int numClientes,
			int[] tipocentrales, double pgarantizados, double[] ptipos, int it,
			int itP, int k, double lambda, int pen, int incPen, int finPen) {
		prTipos = ptipos;
		prContratos = pgarantizados;
		tiposCentrales = tipocentrales;
		nclientes = numClientes;
		this.numreplicas = numreplicas;
		this.solucionInicial = solucionInicial;
		operador = operadores;
		this.It = it;
		this.ItP = itP;
		this.K = k;
		L = lambda;
		pn = pen;
		incPn = incPen;
		finPn = finPen;
		this.nombre = nombre;
	}

	@Override
	public void init() {
		result = new ArrayList<List<String>>();
	}
	
	private void HC (double prTipos[], double prContratos, int tiposCentrales[], int tiposCentralesAux[], int nclientes, int penal) {
		long tiempo = System.currentTimeMillis();
		int semilla = (int) Math.random() * 1000;
		
		Clientes clientes = null;
		
		try {
			clientes = new Clientes(nclientes, prTipos , prContratos, semilla);
		} catch (Exception e1) {
			System.out.println("ERROR AL GENERAR CLIENTES: " + e1.getMessage());
			System.exit(1);
		}
		
		Centrales centrales = null;
		
		try {
			centrales = new Centrales(tiposCentrales, semilla);
		} catch (Exception e1) {
			System.out.println("ERROR AL GENERAR CENTRALES: " + e1.getMessage());
			System.exit(1);
		}
		
		Estado est = new Estado(clientes, centrales, 3);
		est.setIncPenalizacion(penal);
		Problem problemSA = new Problem(est
										, new EnergiaSuccessor()
										, new EnergiaGoalTest()
										, new EnergiaHeuristica());
		
		Search searchSA = new HillClimbingSearch();
		try {
			SearchAgent searchAgent = new SearchAgent(problemSA, searchSA);
			System.out.println(searchAgent.getActions().toString());
			tiempo = System.currentTimeMillis() - tiempo;
			cols.add(String.valueOf(tiempo));
			cols.add("-");
			cols.add(String.valueOf(searchAgent.getActions().size()));
		} catch (Exception e) {
			System.out.println("ERROR: " + e.getMessage());
		}
		result.add(cols);
	}
	
	private void SA (double prTipos[], double prContratos, int tiposCentrales[], int tiposCentralesAux[], int nclientes, int It, int ItP, int K, double L, int penal) {
		long tiempo = System.currentTimeMillis();
		int semilla = (int) Math.random() * 1000;
		
		Clientes clientes = null;
		
		try {
			clientes = new Clientes(nclientes, prTipos , prContratos, semilla);
		} catch (Exception e1) {
			System.out.println("ERROR AL GENERAR CLIENTES: " + e1.getMessage());
			System.exit(1);
		}
		
		Centrales centrales = null;
		
		try {
			centrales = new Centrales(tiposCentrales, semilla);
		} catch (Exception e1) {
			System.out.println("ERROR AL GENERAR CENTRALES: " + e1.getMessage());
			System.exit(1);
		}
		
		Estado est = new Estado(clientes, centrales, 3);
		est.setIncPenalizacion(penal);
		Problem problemSA = new Problem(est
										, new EnergiaSuccessor()
										, new EnergiaGoalTest()
										, new EnergiaHeuristica());
		Search searchSA = new SimulatedAnnealingSearch(It, ItP, K, L);
		try {
			SearchAgent searchAgent = new SearchAgent(problemSA, searchSA);
			cols.add(String.valueOf(tiempo));	
			cols.add("-");
			cols.add("-");
		} catch (Exception e) {
			System.out.println("ERROR: " + e.getMessage());
		}
		tiempo = System.currentTimeMillis() - tiempo;
		cols.add(String.valueOf(tiempo));
		cols.add("-");
		cols.add("-");
		result.add(cols);
	}

	@Override
	public void execute() {
		cols = new ArrayList<String>();
		cols.add("Nombre experimento;");
		cols.add("Algoritmo;");
		cols.add("Put;");
		cols.add("Delete;");
		cols.add("Move;");
		cols.add("Swap;");
		cols.add("Replica;");
		cols.add("Tipo Sol. Ini.;");
		cols.add("N clientes;");
		cols.add("Centrales Tipo A;");
		cols.add("Centrales Tipo B;");
		cols.add("Centrales Tipo C;");
		cols.add("% Garantizados;");
		cols.add("% tipo clientes G;");
		cols.add("% tipo clientes MG;");
		cols.add("% tipo clientes XG;");
		cols.add("Iteraciones");
		cols.add("Iteraciones por paso de temperatura");
		cols.add("K");
		cols.add("Lambda");
		cols.add("Tiempo ms");
		cols.add("Beneficio");
		cols.add("Nodos expandidos");
		result.add(cols);
		int tiposCentralesAux[] = { 5, 10, 25 };
		for(int pn = this.pn; pn < finPn; pn*=incPn) {
			for(int i = 0; i < numreplicas; ++i) {
				cols.add(nombre);
				cols.add("HillClimbing");
				cols.add(String.valueOf(operador[2]));
				cols.add(String.valueOf(operador[1]));
				cols.add(String.valueOf(operador[0]));
				cols.add(String.valueOf(operador[3]));
				cols.add(String.valueOf(i+1));
				cols.add(solucionInicial == 0 ? "linear" : solucionInicial == 1 ? "random" : "greedy");
				cols.add(String.valueOf(nclientes));
				cols.add(String.valueOf(tiposCentrales[0]));
				cols.add(String.valueOf(tiposCentrales[1]));
				cols.add(String.valueOf(tiposCentrales[2]));
				cols.add(String.valueOf(prContratos));
				cols.add(String.valueOf(prTipos[0]));
				cols.add(String.valueOf(prTipos[1]));
				cols.add(String.valueOf(prTipos[2]));
				cols.add("-");
				cols.add("-");
				cols.add("-");
				cols.add("-");
				HC(prTipos, prContratos, tiposCentrales, tiposCentralesAux, nclientes, pn);
			}
			for(int j = 0; j < numreplicas; ++j) {
				cols.add(nombre);
				cols.add("SimulatedAnealling");
				cols.add(String.valueOf(operador[2]));
				cols.add(String.valueOf(operador[1]));
				cols.add(String.valueOf(operador[0]));
				cols.add(String.valueOf(operador[3]));
				cols.add(String.valueOf(j+1));
				cols.add(solucionInicial == 0 ? "linear" : solucionInicial == 1 ? "random" : "greedy");
				cols.add(String.valueOf(nclientes));
				cols.add(String.valueOf(tiposCentrales[0]));
				cols.add(String.valueOf(tiposCentrales[1]));
				cols.add(String.valueOf(tiposCentrales[2]));
				cols.add(String.valueOf(prContratos));
				cols.add(String.valueOf(prTipos[0]));
				cols.add(String.valueOf(prTipos[1]));
				cols.add(String.valueOf(prTipos[2]));
				cols.add(String.valueOf(It));
				cols.add(String.valueOf(ItP));
				cols.add(String.valueOf(K));
				cols.add(String.valueOf(L));
				SA(prTipos, prContratos, tiposCentrales, tiposCentralesAux, nclientes, It, ItP, K, L, pn);
			}
		}
		
	}

	@Override
	public List<List<String>> getResult() {
		// TODO Auto-generated method stub
		return null;
	}

}
